package org.ucas.faker.web.service.Visualization;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.ucas.faker.web.Config.ColorConfig;
import org.ucas.faker.web.Config.VisualConfig;
import org.ucas.faker.web.service.Visualization.entity.AxisParam;
import org.ucas.faker.web.service.Visualization.entity.SeriesParam;
import org.ucas.faker.web.service.Visualization.entity.VisualParam;
import org.ucas.faker.web.service.Visualization.json.DataUtil;

import java.awt.*;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;



@Service
@Transactional
public class OptionService extends VisualService{

    public <T> JSONObject getOption(VisualParam param){
        JSONObject optionJson = new JSONObject();

        //画标题
//        optionJson.put("title", getTitle(param.getGraphName()));

        //画坐标轴
        if (axisPrintable(param.getGraphType())) {
            String targetName = param.getTargetName();
            /*if (param.getGraphType().equals(VisualConfig.TYPE_BUBBLE)){
                targetName = param.getBranchName();
            }*/
            AxisParam axisParamX = new AxisParam();
            AxisParam axisParamY = new AxisParam();

            if (param.getGraphType().equals(VisualConfig.TYPE_STACKSTRIPE)
                    || param.getGraphType().equals(VisualConfig.TYPE_STRIPE)
                    || param.getGraphType().equals(VisualConfig.TYPE_STACKSTRIPERATIO)){
                axisParamX.setName(targetName);
                axisParamX.setLabel(param.getBranchLabel());
                axisParamX.setUnit(param.getTargetUnit());

                axisParamY.setName(param.getBasisName());
                axisParamY.setLabel(param.getBasisLabel());
                axisParamY.setUnit(param.getBasisUnit());

//                optionJson.put("yAxis", getYAxis(param.getGraphType(), param.getBasisLabel(), param.getBasisName()));
//                optionJson.put("xAxis", getXAxis(param.getGraphType(), param.getBranchLabel(), targetName));
            } else if (param.getGraphType().equals(VisualConfig.TYPE_2TARGET)){
                axisParamX.setName(param.getMultiTargetName()[0]);
                axisParamX.setLabel(param.getBasisLabel());
                axisParamX.setUnit(param.getMultiTarget()[0].getUnit());

                axisParamY.setName(param.getMultiTargetName()[1]);
                axisParamY.setLabel(param.getBranchLabel());
                axisParamY.setUnit(param.getMultiTarget()[1].getUnit());

//                optionJson.put("yAxis", getYAxis(param.getGraphType(), param.getBranchLabel(), param.getMultiTargetName()[1]));
//                optionJson.put("xAxis", getXAxis(param.getGraphType(), param.getBasisLabel(), param.getMultiTargetName()[0]));
            } else if (param.getGraphType().equals(VisualConfig.TYPE_BUBBLE)){
                axisParamX.setName(param.getBasisName());
                axisParamX.setLabel(param.getBasisLabel());
                axisParamX.setUnit(param.getBasisUnit());

                axisParamY.setName(param.getBranchName());
                axisParamY.setLabel(param.getBranchLabel());
                axisParamY.setUnit(param.getBranchUnit());
            } else {
                axisParamX.setName(param.getBasisName());
                axisParamX.setLabel(param.getBasisLabel());
                axisParamX.setUnit(param.getBasisUnit());

                axisParamY.setName(targetName);
                axisParamY.setLabel(param.getBranchLabel());
                axisParamY.setUnit(param.getTargetUnit());

//                optionJson.put("yAxis", getYAxis(param.getGraphType(), param.getBranchLabel(), targetName));
//                optionJson.put("xAxis", getXAxis(param.getGraphType(), param.getBasisLabel(), param.getBasisName()));
            }

            optionJson.put("xAxis", getXAxis(param.getGraphType(), axisParamX));
            optionJson.put("yAxis", getYAxis(param.getGraphType(), axisParamY));
        }

        //画toolbox
        optionJson.put("toolbox", getToolbox());

        //画tooltip
        if (param.getGraphType().equals(VisualConfig.TYPE_2TARGET)) {
            optionJson.put("tooltip", getTooltip(param.getGraphType(), param.getBasisName(),
                    param.getMultiTargetName()[0], param.getMultiTargetName()[1]));
        } else {
            optionJson.put("tooltip", getTooltip(param.getGraphType(), param.getBasisName(), param.getBranchName(), param.getTargetName()));
        }

        //画grid
        optionJson.put("grid", getGrid(param.getGraphType(), param.getBranchLabel()));

        //画legend
        if (legendPrintable(param.getGraphType())) {
            if (param.getBasisDimension() == 3) {
                optionJson.put("legend", getLegend(param.getGraphType(), param.getBranchLabel()));
            } else if (param.getBasisDimension() == 2) {
                optionJson.put("legend", getLegend(param.getGraphType(), param.getBasisLabel()));
            }
        }

        //添加颜色
        optionJson.put("color", JSONArray.parseArray(ColorConfig.colorText));

        //画series
        SeriesParam seriesParam = new SeriesParam();
        seriesParam.setGraphType(param.getGraphType());
        seriesParam.setLabel(param.getBasisLabel());
        switch (param.getGraphType()){
            case VisualConfig.TYPE_BUBBLE:
                double min = Double.POSITIVE_INFINITY;
                double max = Double.NEGATIVE_INFINITY;
                for (List<T> dataList : param.getDataArray()){
                    for (T t : dataList) {
                        double value = Double.parseDouble(t.toString());
                        if (value > max) {
                            max = value;
                        }
                        if (value < min) {
                            min = value;
                        }
                    }
                }
                seriesParam.getOption().setMaxValue(max);
                seriesParam.getOption().setMinValue(min);
                break;
            case VisualConfig.TYPE_STACKSTRIPERATIO:
            case VisualConfig.TYPE_STACKBARRATIO:
            case VisualConfig.TYPE_STACKLINERATIO:
                List[] dataArray = param.getDataArray();
                if(dataArray.length==0) break;//这里改zhangyipin
                int listLength = dataArray[0].size();
                int arrayLength = dataArray.length;
                List<Double>[] percentageDataArray = new ArrayList[dataArray.length];
                for (int k=0;k<percentageDataArray.length;k++){
                    percentageDataArray[k] = new ArrayList<Double>();
                }
                for (int j=0;j<listLength;j++){
                    List tmpData = new ArrayList();
                    for (int i=0;i<arrayLength;i++){
                        tmpData.add(dataArray[i].get(j));
                    }
                    List<Double> percentageList = DataUtil.getPercentageData(tmpData);
                    for (int i=0;i<arrayLength;i++) {
                        percentageDataArray[i].add(percentageList.get(i));
                    }
                }
                param.setPercentageDataArray(percentageDataArray);
                break;
            case VisualConfig.TYPE_LINE:
                break;
            default:
                break;
        }

        JSONArray seriesJSONArray = new JSONArray();
        if (param.getBasisDimension() == 3) {
            for (int i = 0; i < param.getBranchLabel().size(); i++) {
                seriesParam.setSeriesName(param.getBranchLabel().getString(i));
                switch (param.getGraphType()) {
                    case VisualConfig.TYPE_STACKSTRIPERATIO:
                    case VisualConfig.TYPE_STACKBARRATIO:
                    case VisualConfig.TYPE_STACKLINERATIO:
                        seriesParam.setDataList(param.getPercentageDataArray()[i]);
                        break;
                    case VisualConfig.TYPE_LINE:
                        seriesParam.setDataList(param.getData(i));
                        seriesParam.getOption().setSymbol(VisualConfig.getSymbol(i));
                        break;
                    default:
                        seriesParam.setDataList(param.getData(i));
                        break;
                }
                seriesJSONArray.add(getSeries(seriesParam));
            }
        } else if (param.getBasisDimension() == 2){
            seriesParam.setSeriesName(param.getBasisName());
            seriesParam.setDataList(param.getData());
            if (param.getGraphType().equals(VisualConfig.TYPE_2TARGET)){
                seriesParam.setMultiDimentionData(param.getMultiDimensionData());
            }
            if (param.getGraphType().equals(VisualConfig.TYPE_LINE)){
                seriesParam.getOption().setSymbol(VisualConfig.getSymbol(0));
            }
            seriesJSONArray.add(getSeries(seriesParam));
        }
        optionJson.put("series", seriesJSONArray);
        return optionJson;
    }

    private boolean axisPrintable(String graphType){
        List<String> typeset = Arrays.asList(VisualConfig.TYPE_STACKBAR, VisualConfig.TYPE_STACKLINE, VisualConfig.TYPE_BUBBLE,
                                             VisualConfig.TYPE_LINE, VisualConfig.TYPE_BAR,
                                             VisualConfig.TYPE_STRIPE, VisualConfig.TYPE_STACKSTRIPE,
                                             VisualConfig.TYPE_2TARGET,
                                             VisualConfig.TYPE_STACKBARRATIO, VisualConfig.TYPE_STACKSTRIPERATIO,
                                             VisualConfig.TYPE_STACKLINERATIO);
        return typeset.contains(graphType);
    }

    private boolean legendPrintable(String graphType){
        List<String> typeset = Arrays.asList(VisualConfig.TYPE_STACKBAR, VisualConfig.TYPE_STACKLINE,
                                             VisualConfig.TYPE_LINE, VisualConfig.TYPE_BAR,
                                             VisualConfig.TYPE_STRIPE, VisualConfig.TYPE_STACKSTRIPE,
                                             VisualConfig.TYPE_STACKSTRIPERATIO, VisualConfig.TYPE_STACKBARRATIO,
                                             VisualConfig.TYPE_STACKLINERATIO
                                             );
        return typeset.contains(graphType);
    }

}
